#ifndef _SYS_VAL_H_
#define _SYS_VAL_H_

#include <stdlib.h>
#include "SysTypes.h"


extern VTable* Obj_classVTable;
extern VTable* Bool_classVTable;
extern VTable* Int_classVTable;
extern VTable* Float_classVTable;


#define VAL_IS_NULL(v)         ((v).vtable == NULL)
#define VAL_GET_VTABLE(v)      ((v).vtable)
#define VAL_GET_BOOL(v)        ((v).val.boolVal)
#define VAL_GET_INT(v)         ((v).val.intVal)
#define VAL_GET_FLOAT(v)       ((v).val.floatVal)
#define VAL_GET_REF(v)         ((v).val.refVal)

#ifndef __cplusplus
#define VAL_NULL               ((struct Val) { .vtable = NULL,              .val = { .refVal = NULL } })
#define VAL_FALSE              ((struct Val) { .vtable = Bool_classVTable,  .val = { .boolVal = FALSE } })
#define VAL_TRUE               ((struct Val) { .vtable = Bool_classVTable,  .val = { .boolVal = TRUE } })
#define VAL_MAKE_BOOL(v)       ((struct Val) { .vtable = Bool_classVTable,  .val = { .boolVal = (v) } })
#define VAL_MAKE_INT(v)        ((struct Val) { .vtable = Int_classVTable,   .val = { .intVal = (v) } })
#define VAL_MAKE_FLOAT(v)      ((struct Val) { .vtable = Float_classVTable, .val = { .floatVal = (v) } })
#define VAL_MAKE_REF(v)        ((struct Val) { .vtable = *((VTable**)(v)),  .val = { .refVal = (v) } })
#else
#define VAL_NULL               (Val::Null())
#define VAL_FALSE              (Val::False())
#define VAL_TRUE               (Val::True())
#define VAL_MAKE_BOOL(v)       (Val::MakeBool(v))
#define VAL_MAKE_INT(v)        (Val::MakeInt(v))
#define VAL_MAKE_FLOAT(v)      (Val::MakeFloat(v))
#define VAL_MAKE_REF(v)        (Val::MakeRef(v))
#endif


/**
 * Val is a struct that can contain any values of Fan:
 *    - type-values: bool, int or float (nullable or not)
 *    - ref-values: any other classes
 */
struct Val
{
  VTable* vtable;
  union
  {
    Bool boolVal;
    Int intVal;
    Float floatVal;
    void* refVal;
  } val;

#ifdef __cplusplus
  static inline Val Null()             { Val v; v.vtable = NULL;              v.val.refVal = NULL;   return v; }
  static inline Val False()            { Val v; v.vtable = Bool_classVTable;  v.val.boolVal = FALSE; return v; }
  static inline Val True()             { Val v; v.vtable = Bool_classVTable;  v.val.boolVal = TRUE;  return v; }
  static inline Val MakeBool(Bool b)   { Val v; v.vtable = Bool_classVTable;  v.val.boolVal = b;     return v; }
  static inline Val MakeInt(Int i)     { Val v; v.vtable = Int_classVTable;   v.val.intVal = i;      return v; }
  static inline Val MakeFloat(Float f) { Val v; v.vtable = Float_classVTable; v.val.floatVal = f;    return v; }
  static inline Val MakeRef(void* ref) { Val v; v.vtable = *((VTable**)ref);  v.val.refVal = ref;    return v; }
#endif
};


#endif
